/*
 * parser.cpp
 *
 *  Created on: 27-Apr-2009
 *      Author: catchthealien
 */

#include <cssysdef.h>

#include <string>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <list>

#include <sys/types.h>
#include <sys/stat.h>
//#include <unistd.h>
#include <errno.h>

#include "parser.h"

using namespace xercesc;
using namespace std;

namespace cta {

/**
 *  Constructor initializes xerces-C libraries.
 *  The XML tags and attributes which we seek are defined.
 *  The xerces-C DOM parser infrastructure is initialized.
 */

parser::parser() {
	// TODO Auto-generated constructor stub
	   try
	   {
	      XMLPlatformUtils::Initialize();  // Initialize Xerces infrastructure
	   }
	   catch( XMLException& e )
	   {
	      char* message = XMLString::transcode( e.getMessage() );
	      cerr << "XML toolkit initialization error: " << message << endl;
	      XMLString::release( &message );
	      // throw exception here to return ERROR_XERCES_INIT
	   }

	}

	/**
	 *  Class destructor frees memory used to hold the XML tag and
	 *  attribute definitions. It als terminates use of the xerces-C
	 *  framework.
	 */

parser::~parser() {
	// TODO Auto-generated destructor stub

try
{
   XMLPlatformUtils::Terminate();  // Terminate Xerces
}
catch( xercesc::XMLException& e )
{
   char* message = xercesc::XMLString::transcode( e.getMessage() );

   cerr << "XML ttolkit teardown error: " << message << endl;
   XMLString::release( &message );
}

}

int parser::getInteger(char* configFile, char* p_tag, char* p_attr)
{
	std::string strConfigFile = configFile;
	std::string strP_tag = p_tag;
	std::string strP_attr = p_attr;
	return getInteger(strConfigFile, strP_tag, strP_attr);
}

int parser::getInteger(std::string& configFile, char* p_tag, char* p_attr)
{
	std::string strP_tag = p_tag;
	std::string strP_attr = p_attr;
	return getInteger(configFile, strP_tag, strP_attr);
}

int parser::getInteger(std::string& configFile, std::string& p_tag, std::string& p_attr)
{
	std::stringstream return_(getString(configFile,p_tag,p_attr));
	int returni_ = (-1);
	return_ >> returni_;
	return returni_;
}

int parser::getIntegerFromString(std::string& configFile, char* p_tag, char* p_attr)
{
	std::string strP_tag = p_tag;
	std::string strP_attr = p_attr;
	return getIntegerFromString(configFile, strP_tag, strP_attr);
}

int parser::getIntegerFromString(std::string& configFile, std::string& p_tag, std::string& p_attr)
{
	std::stringstream return_(getStringFromString(configFile,p_tag,p_attr));
	int returni_ = (-1);
	return_ >> returni_;
	return returni_;
}

float parser::getFloatFromString(std::string& configFile, char* p_tag, char* p_attr)
{
	std::string strP_tag = p_tag;
	std::string strP_attr = p_attr;
	return getFloatFromString(configFile, strP_tag, strP_attr);
}

float parser::getFloatFromString(std::string& configFile, std::string& p_tag, std::string& p_attr)
{
	std::stringstream return_(getStringFromString(configFile,p_tag,p_attr));
	float returnf_ = (-1);
	return_ >> returnf_;
	return returnf_;
}

std::string parser::getString(std::string& configFile, char* p_tag, char* p_attr)
{
	std::string p_tag_ = p_tag;
	std::string p_attr_ = p_attr;
	return getString(configFile, p_tag_, p_attr_);
}

std::string parser::getString(std::string& configFile, std::string& p_tag, std::string& p_attr)
	throw( std::runtime_error )
{
	FileParser_ = new XercesDOMParser;
   // Test to see if the file is ok.

   struct stat fileStatus;

   int iretStat = stat(configFile.c_str(), &fileStatus);
   if( iretStat == ENOENT )
      throw ( std::runtime_error("Path file_name does not exist, or path is an empty string.") );
   else if( iretStat == ENOTDIR )
      throw ( std::runtime_error("A component of the path is not a directory."));
//   else if( iretStat == ELOOP )
//      throw ( std::runtime_error("Too many symbolic links encountered while traversing the path."));
   else if( iretStat == EACCES )
      throw ( std::runtime_error("Permission denied."));
   else if( iretStat == ENAMETOOLONG )
      throw ( std::runtime_error("File can not be read\n"));
	// Configure DOM parser.

	   FileParser_->setValidationScheme( XercesDOMParser::Val_Never );
	   FileParser_->setDoNamespaces( false );
	   FileParser_->setDoSchema( false );
	   FileParser_->setLoadExternalDTD( false );

	   try
	      {
	         FileParser_->parse( configFile.c_str() );

	         // no need to free this pointer - owned by the parent parser object
	         DOMDocument* xmlDoc = FileParser_->getDocument();

	         // Get the top-level element: NAme is "root". No attributes for "root"

	         DOMElement* elementRoot = xmlDoc->getDocumentElement();
	         if( !elementRoot ) throw(std::runtime_error( "empty XML document" ));

	         // Parse XML file for tags of interest: "ApplicationSettings"
	         // Look one level nested within "root". (child of root)

	         DOMNodeList*      children = elementRoot->getChildNodes();
	         const  XMLSize_t nodeCount = children->getLength();

	         // For all nodes, children of "root" in the XML tree.

	         for( XMLSize_t xx = 0; xx < nodeCount; ++xx )
	         {
	            DOMNode* currentNode = children->item(xx);
	            if( currentNode->getNodeType() &&  // true is not NULL
	                currentNode->getNodeType() == DOMNode::ELEMENT_NODE ) // is element
	            {
	               // Found node which is an Element. Re-cast node as element
	               DOMElement* currentElement
	                           = dynamic_cast< xercesc::DOMElement* >( currentNode );
	               if( XMLString::equals(currentElement->getTagName(), XMLString::transcode(p_tag.c_str())))
	               {
	                  // Already tested node as type element and of name "ApplicationSettings".
	                  // Read attributes of element "ApplicationSettings".
	                  std::string return_ = xercesc::XMLString::transcode(
										  currentElement->getAttribute(XMLString::transcode(p_attr.c_str())));
	                  return return_;
	               }
	            }
	         }
	      }
	      catch( xercesc::XMLException& e )
	      {
	         char* message = xercesc::XMLString::transcode( e.getMessage() );
	         ostringstream errBuf;
	         errBuf << "Error parsing file: " << message << flush;
	         XMLString::release( &message );
	      }

	      return "";
}

std::string parser::getStringFromString(std::string& p_String, char* p_tag, char* p_attr)
{
	std::string p_tag_ = p_tag;
	std::string p_attr_ = p_attr;
	return getStringFromString(p_String, p_tag_, p_attr_);
}

std::string parser::getStringFromString(std::string& p_String, std::string& p_tag, std::string& p_attr)
{

	StringParser_ = new XercesDOMParser;
		   StringParser_->setValidationScheme( XercesDOMParser::Val_Never );
		   StringParser_->setDoNamespaces( false );
		   StringParser_->setDoSchema( false );
		   StringParser_->setLoadExternalDTD( false );

		   try
		      {
			   StringParser_ = new XercesDOMParser();
			   InputSource* inSource = new MemBufInputSource((const unsigned char*)p_String.c_str(), p_String.length(), "1", false);
			   StringParser_->parse(*inSource);
			   delete inSource;
		        DOMDocument* xmlDoc = StringParser_->getDocument();

		         // Get the top-level element: NAme is "root". No attributes for "root"

		         DOMElement* elementRoot = xmlDoc->getDocumentElement();
		         if( !elementRoot ) throw(std::runtime_error( "empty XML document" ));

		         // Parse XML file for tags of interest: "ApplicationSettings"
		         // Look one level nested within "root". (child of root)

		         DOMNodeList*      children = elementRoot->getChildNodes();
		         const  XMLSize_t nodeCount = children->getLength();

		         // For all nodes, children of "root" in the XML tree.

		         for( XMLSize_t xx = 0; xx < nodeCount; ++xx )
		         {
		            DOMNode* currentNode = children->item(xx);
		            if( currentNode->getNodeType() &&  // true is not NULL
		                currentNode->getNodeType() == DOMNode::ELEMENT_NODE ) // is element
		            {
		               // Found node which is an Element. Re-cast node as element
		               DOMElement* currentElement
		                           = dynamic_cast< xercesc::DOMElement* >( currentNode );
		               if( XMLString::equals(currentElement->getTagName(), XMLString::transcode(p_tag.c_str())))
		               {
		                  // Already tested node as type element and of name "ApplicationSettings".
		                  // Read attributes of element "ApplicationSettings".
		                  std::string return_ = xercesc::XMLString::transcode(
											  currentElement->getAttribute(XMLString::transcode(p_attr.c_str())));
		                  return return_;
		               }
		            }
		         }
		      }
		      catch( xercesc::XMLException& e )
		      {
		         char* message = xercesc::XMLString::transcode( e.getMessage() );
		         ostringstream errBuf;
		         errBuf << "Error parsing file: " << message << flush;
		         XMLString::release( &message );
		      }

		      return "";

}

}
